package shoppingcart

import (
	"context"
	"fmt"
	"strings"

	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/order/model"
	"mall/service/order/rpc/internal/svc"
	"mall/service/order/rpc/types/order"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetShoppingCartLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetShoppingCartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetShoppingCartLogic {
	return &GetShoppingCartLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetShoppingCartLogic) GetShoppingCart(in *order.BaseListReq) (*order.ShoppingCartResp, error) {
	// logrus.Info(fmt.Sprintf("GetShoppingCart BaseListReq: %+v", in))
	// Limit:10  Preload:"cartItem:Id,SkuId,ProductId,OrderId,GemPrice,RetailPrice,Quantity,Status,Favorable,Memo"  Filter:"UserId,equalTo:10021;Status,notEqualTo:3"  VisitorId:10021  PlatformId:1

	if in.Filter == nil || len(*in.Filter) == 0 {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)
	// logrus.Info(fmt.Sprintf("GetShoppingCart preloadMap: %+v", preloadMap))
	// map[cartItem:[Id SkuId ProductId OrderId GemPrice RetailPrice Quantity Status Favorable Memo]]
	logrus.Info(fmt.Sprintf("GetShoppingCart eagerLoadMap: %+v", eagerLoadMap))
	// map[]

	cartItemEntityName := model.RpcEntityNames.CartItem
	if _, ok := model.RpcEntityPreloadMap[cartItemEntityName]; !ok {
		return &order.ShoppingCartResp{}, nil
	}

	cartItemRepositoryName := model.RepositoryNames.CartItem
	columnMap, ok := model.RepositoryPreloadMap[cartItemRepositoryName]
	if !ok {
		return &order.ShoppingCartResp{}, nil
	}

	var selectCols []string
	if preloadFields, ok := preloadMap[cartItemEntityName]; ok {
		selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
	}

	filterMap := modelx.ParseFilter(in.Filter, columnMap)
	// logrus.Info(fmt.Sprintf("GetShoppingCart filterMap: %+v", filterMap))
	// map[status:map[notEqualTo:[3]] user_id:map[equalTo:[10021]]]
	if filterMap == nil {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	orderBy := modelx.ParseSorter(in.Sorter, columnMap)
	logrus.Info(fmt.Sprintf("GetShoppingCart orderBy: %s", orderBy))
	//
	if len(orderBy) == 0 {
		orderBy = model.CartItemColumns.ID + " DESC"
	}

	res, count, err := l.svcCtx.Cart.GetList(l.ctx, model.M{
		"offset":  in.Offset,
		"limit":   in.Limit,
		"orderBy": orderBy,
		"select":  strings.Join(selectCols, ","),
	}, 2, filterMap)
	if err != nil {
		return nil, err
	}

	hasNextPage, hasPreviousPage := modelx.ParseCount(count)
	resp := &order.ShoppingCartResp{
		HasNextPage:     &hasNextPage,
		HasPreviousPage: &hasPreviousPage,
	}

	skuIdMap := make(map[any]bool)
	if len(res) > 0 {
		for _, v := range res {
			skuIdMap[int64(v.SkuID)] = true
			resp.List = append(resp.List, &order.ShoppingCartItemInfo{
				Id:          &v.ID,
				UserId:      &v.UserID,
				SkuId:       &v.SkuID,
				Sku:         &v.Sku,
				SkuImageUrl: &v.SkuImageURL,
				ProductId:   &v.ProductID,
				OrderId:     &v.OrderID,
				Title:       &v.Title,
				Slug:        &v.Slug,
				BrandId:     &v.BrandID,
				BrandTitle:  &v.BrandTitle,
				BrandSlug:   &v.BrandSlug,
				RetailPrice: pointy.GetPointer(moneyx.FormatAmount(int64(v.RetailPrice))),
				Quantity:    pointy.GetPointer(uint32(v.Quantity)),
				Status:      pointy.GetPointer(int32(v.Status)),
				Favorable:   pointy.GetPointer(uint32(v.Favorable)),
				Memo:        &v.Memo,
				PostId:      &v.PostID,
				InviterId:   &v.InviterID,
			})
		}
	}

	if in.Prefetch != nil {
		if skuIds := modelx.UniqueInterfaces(strings.TrimSpace(*in.Prefetch), 64); len(skuIds) > 0 {
			var prefetchIds []any
			for _, skuId := range skuIds {
				if _, ok := skuIdMap[skuId]; !ok {
					prefetchIds = append(prefetchIds, skuId)
				}
			}
			if len(prefetchIds) > 0 {
				filterMap[model.CartItemColumns.SkuID] = map[string][]any{
					"in": prefetchIds,
				}
				prefetchRes, _, err := l.svcCtx.Cart.GetList(l.ctx, model.M{
					"orderBy": orderBy,
					"select":  strings.Join(selectCols, ","),
				}, -1, filterMap)
				if err != nil {
					return nil, err
				}

				if len(prefetchRes) > 0 {
					for _, v := range prefetchRes {
						resp.List = append(resp.List, &order.ShoppingCartItemInfo{
							Id:          &v.ID,
							UserId:      &v.UserID,
							SkuId:       &v.SkuID,
							Sku:         &v.Sku,
							SkuImageUrl: &v.SkuImageURL,
							ProductId:   &v.ProductID,
							OrderId:     &v.OrderID,
							Title:       &v.Title,
							Slug:        &v.Slug,
							BrandId:     &v.BrandID,
							BrandTitle:  &v.BrandTitle,
							BrandSlug:   &v.BrandSlug,
							RetailPrice: pointy.GetPointer(moneyx.FormatAmount(int64(v.RetailPrice))),
							Quantity:    pointy.GetPointer(uint32(v.Quantity)),
							Status:      pointy.GetPointer(int32(v.Status)),
							Favorable:   pointy.GetPointer(uint32(v.Favorable)),
							Memo:        &v.Memo,
							Prefetched:  pointy.GetPointer(uint32(1)),
							PostId:      &v.PostID,
							InviterId:   &v.InviterID,
						})
					}
				}
			}
		}
	}

	return resp, nil
}
